package com.binary.util;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//import org.apache.http.entity.mime.MultipartEntityBuilder;


import com.alibaba.fastjson.JSONObject;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Jzli on 2016-01-08.
 */
public class HttpClientUtils {
	private static final Logger LOGGER = LoggerFactory
			.getLogger(HttpClientUtils.class);

	enum Setting {
		DEFAULT(60, 30, "UTF-8", "application/json");

		int socketTimeout;
		int connectTimeout;
		String charset;
		String contentType;

		Setting(int socketTimeout, int connectTimeout, String charset,
				String contentType) {
			this.socketTimeout = socketTimeout;
			this.connectTimeout = connectTimeout;
			this.charset = charset;
			this.contentType = contentType;
		}
	}

	// 使用连接池
	private static PoolingHttpClientConnectionManager cm;

	static {
		cm = new PoolingHttpClientConnectionManager();
		// 设置连接池的最大连接数
		cm.setMaxTotal(100);
		// 设置每个路由上的默认连接个数
		cm.setDefaultMaxPerRoute(50);
	}

	/**
	 * 通过get方式获取指定地址的内容
	 * 
	 * @param url
	 *            需要访问的地址如：http://www.cpic.com.cn
	 * @param socketTimeout
	 * @param connectTimeout
	 * @param charset
	 * @return
	 * @throws IOException
	 */
	public static String get(String url, int socketTimeout, int connectTimeout,
			String charset) throws IOException {
		if (charset == null || "".equals(charset)) {
			charset = Setting.DEFAULT.charset;
		}
		if (socketTimeout < 0) {
			socketTimeout = Setting.DEFAULT.socketTimeout;
		}
		if (connectTimeout < 0) {
			connectTimeout = Setting.DEFAULT.socketTimeout;
		}

		// 从连接池中获取http client
		CloseableHttpClient httpClient = HttpClients.custom()
				.setConnectionManager(cm).build();

		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(socketTimeout * 1000)
				.setConnectTimeout(connectTimeout * 1000).build();

		HttpGet httpGet = new HttpGet(url);
		httpGet.setConfig(requestConfig);

		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(httpGet);
			return getResponseBody(response, charset);
		} finally {
			if (response != null) {
				response.close();
			}
		}
	}
	/**
	 * 通过get方式文件流信息
	 * InputStream
	 * @param url
	 *   需要访问的地址如：http://www.cpic.com.cn
	 * @param socketTimeout
	 * @param connectTimeout
	 * @param charset
	 * @return
	 * @throws IOException
	 */
	public static File getInputStream(String url, int socketTimeout, int connectTimeout,File file) throws IOException {
		
		if (socketTimeout < 0) {
			socketTimeout = Setting.DEFAULT.socketTimeout;
		}
		if (connectTimeout < 0) {
			connectTimeout = Setting.DEFAULT.socketTimeout;
		}

		// 从连接池中获取http client
		CloseableHttpClient httpClient = HttpClients.custom()
				.setConnectionManager(cm).build();

		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(socketTimeout * 1000)
				.setConnectTimeout(connectTimeout * 1000).build();

		HttpGet httpGet = new HttpGet(url);
		httpGet.setConfig(requestConfig);

		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(httpGet);
			return dwInputStream(response,file);
		} finally {
			if (response != null) {
				response.close();
			}
		}
	}
	
	/**
	 * 使用gett方式提交参数
	 * 参数放入header中
	 * @param url
	 * @param json
	 * @param paramsHead
	 * @param socketTimeout
	 * @param connectTimeout
	 * @param charset
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String get(String url, Map<String, String> paramsHead, int socketTimeout,
			int connectTimeout, String charset) throws IOException {
		if (socketTimeout < 0) {
			socketTimeout = Setting.DEFAULT.socketTimeout;
		}
		if (connectTimeout < 0) {
			connectTimeout = Setting.DEFAULT.socketTimeout;
		}
		if (charset == null || "".equals(charset)) {
			charset = Setting.DEFAULT.charset;
		}

		// 从连接池中获取http client
		CloseableHttpClient httpClient = HttpClients.custom()
				.setConnectionManager(cm).build();

		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(socketTimeout * 1000)
				.setConnectTimeout(connectTimeout * 1000).build();

		HttpGet httpGet = new HttpGet(url);
		httpGet.setConfig(requestConfig);

		if (null != paramsHead) {
			for (Map.Entry<String, String> entry : paramsHead.entrySet()) {
				httpGet.addHeader(entry.getKey(), entry.getValue());
			}
		}
		CloseableHttpResponse response = null;

		try {
			response = httpClient.execute(httpGet);
			return getResponseBody(response, charset);
		} finally {
			if (response != null) {
				response.close();
			}
		}
	}
	
	
	/**
	 * 使用post方式提交参数
	 * 
	 * @param url
	 * @param json
	 * @param paramsHead
	 * @param socketTimeout
	 * @param connectTimeout
	 * @param charset
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String post(String url, String json,
			Map<String, String> paramsHead, int socketTimeout,
			int connectTimeout, String charset) throws IOException {
		if (socketTimeout < 0) {
			socketTimeout = Setting.DEFAULT.socketTimeout;
		}
		if (connectTimeout < 0) {
			connectTimeout = Setting.DEFAULT.socketTimeout;
		}
		if (charset == null || "".equals(charset)) {
			charset = Setting.DEFAULT.charset;
		}

		// 从连接池中获取http client
		CloseableHttpClient httpClient = HttpClients.custom()
				.setConnectionManager(cm).build();

		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(socketTimeout * 1000)
				.setConnectTimeout(connectTimeout * 1000).build();

		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(requestConfig);

		if (null != paramsHead) {
			for (Map.Entry<String, String> entry : paramsHead.entrySet()) {
				httpPost.addHeader(entry.getKey(), entry.getValue());
			}
		}

		StringEntity entity = new StringEntity(json, charset);
		httpPost.setEntity(entity);
		CloseableHttpResponse response = null;

		try {
			response = httpClient.execute(httpPost);
			return getResponseBody(response, charset);
		} finally {
			if (response != null) {
				response.close();
			}
		}
	}

	/**
	 * @param url
	 * @param params
	 * @param socketTimeout
	 * @param connectTimeout
	 * @param charset
	 * @return
	 * @throws IOException
	 */
	public static String post(String url, Map<String, Object> params,
			int socketTimeout, int connectTimeout, String charset,
			String contentType) throws IOException {
		if (socketTimeout < 0) {
			socketTimeout = Setting.DEFAULT.socketTimeout;
		}
		if (connectTimeout < 0) {
			connectTimeout = Setting.DEFAULT.socketTimeout;
		}
		if (charset == null || "".equals(charset)) {
			charset = Setting.DEFAULT.charset;
		}
		if (contentType == null || "".equals(contentType)) {
			contentType = Setting.DEFAULT.contentType;
		}
		// 从连接池中获取http client
		CloseableHttpClient httpClient = HttpClients.custom()
				.setConnectionManager(cm).build();

		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(socketTimeout * 1000)
				.setConnectTimeout(connectTimeout * 1000).build();

		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(requestConfig);

		if (contentType.equals(Setting.DEFAULT.contentType)) {
			StringEntity entity = new StringEntity(
					JSONObject.toJSONString(params), charset);
		//	LOGGER.debug(JSONObject.toJSONString(params));
			entity.setContentType(contentType);
			httpPost.setEntity(entity);
		} else {
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
			for (Map.Entry<String, Object> entry : params.entrySet()) {
				nvps.add(new BasicNameValuePair(entry.getKey(), (String) entry
						.getValue()));
			}
			UrlEncodedFormEntity entity = new UrlEncodedFormEntity(nvps,
					charset);
			httpPost.setEntity(entity);
		}

		CloseableHttpResponse response = null;

		try {
			response = httpClient.execute(httpPost);
			return getResponseBody(response, charset);
		} finally {
			if (response != null) {
				response.close();
			}
		}
	}

	public static String post(String url, Map<String, Object> params)
			throws IOException {
		return post(url, params, Setting.DEFAULT.socketTimeout,
				Setting.DEFAULT.socketTimeout, Setting.DEFAULT.charset,
				Setting.DEFAULT.contentType);
	}
	
	
	
	/**
	 * 上传操作 
	 * post请求
	 * @param url
	 * @param 
	 * @param socketTimeout
	 * @param connectTimeout
	 * @param charset
	 * @return
	 * @throws IOException
	 */
	public static String postUploadImg(String url, String name,File file ,
			int socketTimeout, int connectTimeout, String charset) throws IOException {
		if (socketTimeout < 0) {
			socketTimeout = Setting.DEFAULT.socketTimeout;
		}
		if (connectTimeout < 0) {
			connectTimeout = Setting.DEFAULT.socketTimeout;
		}
		if (charset == null || "".equals(charset)) {
			charset = Setting.DEFAULT.charset;
		}

		// 从连接池中获取http client
		CloseableHttpClient httpClient = HttpClients.custom()
				.setConnectionManager(cm).build();

		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(socketTimeout * 1000)
				.setConnectTimeout(connectTimeout * 1000).build();

		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(requestConfig);
		
		MultipartEntityBuilder builder = MultipartEntityBuilder.create();
		builder.addTextBody("name", name, ContentType.create("text/plain", Consts.UTF_8));
		builder.addTextBody("path", "temp", ContentType.create("text/plain", Consts.UTF_8));
		builder.addTextBody("notes", "测试上传是否成功1", ContentType.create("text/plain", Consts.UTF_8));
		builder.addTextBody("key1", "11111", ContentType.create("text/plain", Consts.UTF_8));
		builder.addBinaryBody("file", file);
	     httpPost.setEntity(builder.build());
    	CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(httpPost);
			return getResponseBody(response, charset);
		} finally {
			if (response != null) {
				response.close();
			}
		}
	}
	
	private static String getResponseBody(CloseableHttpResponse response,
			String charset) throws IOException {
		HttpEntity httpEntity = response.getEntity();

		String responseBody = EntityUtils.toString(httpEntity, charset);
		EntityUtils.consume(httpEntity);

		StatusLine statusLine = response.getStatusLine();
		int statusCode = statusLine.getStatusCode();
		if (statusCode != 200) {
			byte[] responseBytes = Base64.encodeBase64(responseBody.getBytes(),
					true);
			String responseBodyLog = new String(responseBytes);

			LOGGER.error("Request url error, statusCode:{}, responseBody:{}",
					statusCode, responseBodyLog);
			throw new IOException("Request url statusCode is " + statusCode);
		}
		return responseBody;
	}
	
	  /**
	   * 获取流
	   * @param response
	   * @return
	   * @throws IOException
	   */
	
	private static File dwInputStream(CloseableHttpResponse response,File file) throws IOException {
		HttpEntity httpEntity = response.getEntity();

		InputStream in = httpEntity.getContent();
		FileUtils.copyInputStreamToFile( in, file);
		EntityUtils.consume(httpEntity);

		StatusLine statusLine = response.getStatusLine();
		int statusCode = statusLine.getStatusCode();
		if (statusCode != 200) {
		
			LOGGER.error("Request url error, statusCode:{}, responseBody:{}",
					statusCode,"获取流信息失败");
			throw new IOException("Request url statusCode is " + statusCode);
		}
		return file;
	}
	
}
